package org.dhbw.oodb.dmlp;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.dhbw.oodb.dmlp.dao.CustomerDaoImpl;
import org.dhbw.oodb.dmlp.dao.CustomerJPADao;
import org.dhbw.oodb.dmlp.entity.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("benchmark")
public class Benchmark {
	
	private InputStream file;
	private Scanner scanner;
	
	
	private CustomerDaoImpl customerDAO;
	private EntityManager entityManager;
	private ArrayList<Customer> customers;
	
	public long SNTJDBC = 0;
	
	public Benchmark(){
		this.InitializeFilestream();
		this.customers = new ArrayList<Customer>();
	}
	
	private void InitializeFilestream(){
		
		this.file = this.getClass().getResourceAsStream("/customer.tbl");
		this.scanner = new Scanner(this.file);
	}
	
	/**
	 * Load the given count(amount) of Customer-objects out of the File
	 * @param count
	 * @return boolean - true if there still are rows left, false if the end of the list was reached
	 */
	public boolean LoadNextObjects(int count){
		
		this.customers.clear();
		
		while(this.scanner.hasNextLine()){
			if(count==0){
				break;
			}
			
			String line = this.scanner.nextLine();
			String[] nextLine = line.split("\\|");
			
			//Store the extracted lines within the customer-object
			
			Customer cust = new Customer();
			
			cust.setC_custkey(Long.parseLong(nextLine[0]));
			cust.setC_name(nextLine[1]);
			cust.setC_address(nextLine[2]);
			cust.setC_nationkey(Integer.parseInt(nextLine[3]));
			cust.setC_phone(nextLine[4]);
			cust.setC_acctbal(Double.parseDouble(nextLine[5]));
			cust.setC_mktsegment(nextLine[6]);
			cust.setC_comment(nextLine[7]);
			
			this.customers.add(cust);
			
			count--;
		}
		
		if(this.scanner.hasNext() || !this.customers.isEmpty()){
			return(true);
		}
		else{
			return(false);
		}
	}
	
	
	public void BenchmarkSpringSingleTransaction(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			
			for(Customer cust : this.customers){
				this.customerDAO.insert(cust);
			}
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	public void BenchmarkSpringCustomTransaction(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			
			this.customerDAO.insert(this.customers);
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	
	public void BenchmarkSpringBatch(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			
			
			try {
				this.customerDAO.batchInsert(this.customers);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	public void BenchmarkSpringPreparedBatch(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			
			
			try {
				this.customerDAO.batchInsertPrepared(this.customers);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	public void BenchmarkJPASingleTransaction(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		EntityTransaction entityTransaction = this.entityManager.getTransaction();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			
			for(Customer cust: this.customers){
				entityTransaction.begin();
				this.entityManager.persist(cust);
				entityTransaction.commit();
			}
			this.entityManager.clear();
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	public void BenchmarkJPACustomTransaction(int buffersize){
		System.out.println("Truncating currrent Customer's");
		
		this.customerDAO.truncate();
		
		int count=buffersize;
		
		this.SNTJDBC = System.currentTimeMillis();
		
		System.out.println("Inserting...");
		
		this.InitializeFilestream();
		
		EntityTransaction entityTransaction = this.entityManager.getTransaction();
		
		while(this.LoadNextObjects(buffersize)){
			//System.out.println(count);
			count+=buffersize;
			entityTransaction.begin();
			
			for(Customer cust: this.customers){
				
				this.entityManager.persist(cust);
				
			}
			
			entityTransaction.commit();
			this.entityManager.clear();
		}
		
		this.SNTJDBC = System.currentTimeMillis() - this.SNTJDBC;
	}
	
	@Autowired
	public void setCustomerDAO(CustomerDaoImpl customerDAO) {
		this.customerDAO = customerDAO;
	}

	public CustomerDaoImpl getCustomerDAO() {
		return this.customerDAO;
	}
	

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

}
